/**
 * Project: HLA-OMNeT++: Omnet hla compliant version
 * File name: Start.java
 * Description:  Starts the Omnet federate. It should be modified according to our federation.
 *   
 * @author Emanuele Galli and Gaetano Cavarretta, Universita' di Roma Tor Vergata
 * @version v 1.0
 *   
 * @see The GNU Public License (GPL)
 */

/**    This file is part of HLA-OMNeT++.

    HLA-OMNeT++ is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    HLA-OMNeT++ is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with HLA-OMNeT++.  If not, see <http://www.gnu.org/licenses/>.
*/

package federateOmnet;

import hla.rti1516.FederateNotExecutionMember;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
//import java.net.ServerSocket;
import java.net.Socket;
import java.util.StringTokenizer;


public class Start {
	static final int MAX_REQ = 5;
	/**
	 * @param args
	 */
	public  Socket socketClient;
	public  OutputStream oStream=null;
	public  InputStream iStream=null;
	private String bufferReceiveString;

	public static String rtiAddressDefault="127.0.0.1";
	private byte[] bufferReceiveByte=new byte[2000];
	
	
	private void inizializeFederate(OmnetFederate omnet) {
		
		omnet.getAmbassadors();
		omnet.joinFederation("FEDERATION");
		omnet.isTimeRegulating();
		omnet.isTimeConstrained();
		
		omnet.getInteractionHandle("ResponseToRepast");
		omnet.publishInteraction(omnet.getIhMessageResponse());
		
		/* old fed sync */
		omnet.getInteractionHandle("JoinedOmnet");
		omnet.publishInteraction(omnet.getIhMessageJoinFederation());
		/**/
		
		omnet.getInteractionHandle("RequestToOmnet");
		omnet.subscribeInteraction(omnet.getIhMessageRequest());
		
		omnet.getInteractionHandle("SendFailure");
		omnet.subscribeInteraction(omnet.getIhMessageFailure());
		
		omnet.getInteractionHandle("SendRecovery");
		omnet.subscribeInteraction(omnet.getIhMessageRecovery());
		
		omnet.getInteractionHandle("BackgroundTraffic");
		omnet.subscribeInteraction(omnet.getIhMessageBackground());
		
		//avviso tutti che sto nella federazione
			
		
		@SuppressWarnings("unused")
		ReadXml netXml=new ReadXml("network.xml",omnet);
		omnet.sendMessage(new Boolean(true),omnet.getIhMessageJoinFederation());
		/** FED SYNC BY REFERENCE **/
		/*	
		try {
			System.out.println ("[OMNET] Waiting for federation to be sync on starting point");
			// 1. Wait for the "start" sync point to be announced by the RTI
			while(!omnet.startSyncPointAnnounced){
				omnet.getRti().evokeMultipleCallbacks(0.1, 1.0);
			}
			// 2. Achieve "start" point synchronization
			omnet.getRti().synchronizationPointAchieved("start");
			// 3. Wait for the federation to be in sync
			while(!omnet.startSyncPointAchieved){
				omnet.getRti().evokeMultipleCallbacks(0.1, 1.0);
			}
		} catch (FederateNotExecutionMember e) {
			System.out.println("Cannot sync if it is not a federatiom member");
			System.exit(1);
		} catch (Exception e) {
			e.printStackTrace();
		}
		*/
		//omnet.sendMessage(new Boolean(true), omnet.getIhMessageJoinFederation());
		//omnet.timeAdvanceAndCallback();
		omnet.getSynchronized("StartTest");
		omnet.getSynchronized("EndTest");
		
		try {
			//omnet.sendMessage(new Boolean(true), omnet.getIhMessageJoinFederation());
			System.out.println("*******************start omnet*******************");
			String temp="Start Omnet:"+omnet.getCurrentFederateTime().getTime()+"\r\n\r\n";
			this.oStream.write((temp).getBytes());
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	private ResponseToRepast createResponseToRepast(String value){
		char ch='"';
		StringTokenizer st = new StringTokenizer(value,""+ch);
	
		ResponseToRepast response=new ResponseToRepast();
		while (st.hasMoreTokens()) {
			String kind = st.nextToken().trim();
			if(kind.contains("messageResponseCOM"))
			{
				
				response.setId(new Integer(st.nextToken().trim()).intValue());
				
				st.nextToken();
				response.setSource(st.nextToken().trim());
				
				st.nextToken();
				response.setDestination(st.nextToken().trim());
				
				st.nextToken();
				response.setStatus(st.nextToken().trim());				
				
				st.nextToken();								
				response.setDelay(parseDelay(st.nextToken()));
						
			}
								
		}
		
		return response;
	}
	private double parseDelay(String s){
		StringTokenizer st = new StringTokenizer(s, "(");
		return new Double(st.nextToken().trim()).doubleValue();
		
	}
	public void readFromServer(OmnetFederate omnet) {
	
		try {
			int offset=0;
			while(!(new String(bufferReceiveByte).contains("\r\n\r\n"))){
				
				this.iStream.read(bufferReceiveByte,offset,1);
				offset++;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		bufferReceiveString=new String(bufferReceiveByte);
		StringTokenizer st=new StringTokenizer(bufferReceiveString,"\r\n\r\n");
		
		while(st.hasMoreTokens()){
			String temp=st.nextToken();
			if(temp.contains("nextMessageRequest")){
				omnet.timeAdvanceAndCallback();
			}
			else if(temp.contains("messageResponseCOM")){
				omnet.sendMessage(this.createResponseToRepast(temp), omnet.getIhMessageResponse());
			}
		}
		bufferReceiveString=null;
		bufferReceiveByte=new byte[2000];
	}
	
	public static void main(String[] args) {
		Start start=null;
		String comnet=null;
		if(args.length>0) {
			start=new Start(args[0]);
			comnet=args[1];
		} else {
			start=new Start(rtiAddressDefault);
			comnet="127.0.0.1";
		}
		try {
			start.socketClient = new Socket(comnet, 2682);
			start.oStream = start.socketClient.getOutputStream();
			start.iStream = start.socketClient.getInputStream();
			@SuppressWarnings("unused")
			OmnetFederate omnet = new OmnetFederate(start);
			start.inizializeFederate(omnet);
				    
			
			while(true){
				
				int index=0;
				while(index<omnet.getUpdateFailureRecovery().size()){
					String value=(String)omnet.getUpdateFailureRecovery().get(index);
					if(value.contains("Failure")){
						StringTokenizer st=new StringTokenizer(value,":");
						String istanceName=null;
						while(st.hasMoreTokens()){
							String temp=(String)st.nextElement();
							if(!temp.equals("Failure"))
								istanceName=temp;
						}
						
						String nameObject=(String)omnet.getMappingInstanceToClass().get(istanceName);
						System.out.println("Failure:["+istanceName+"] nameObject:["+nameObject+"]");
						String []attributeValue=new String[1];
						String [] attributeName=new String[1];
						attributeValue[0]="off";
						attributeName[0]="Status";
						omnet.updateObjectAttribute(nameObject, attributeValue, istanceName, attributeName);
					}
					else if(value.contains("Recovery")){
						StringTokenizer st=new StringTokenizer(value,":");
						String istanceName=null;
						while(st.hasMoreTokens()){
							String temp=(String)st.nextElement();
							if(!temp.equals("Recovery"))
								istanceName=temp;
						}
						
						String nameObject=(String)omnet.getMappingInstanceToClass().get(istanceName);
						System.out.println("Recovery:["+istanceName+"] nameObject:["+nameObject+"]");
						String []attributeValue=new String[1];
						String [] attributeName=new String[1];
						attributeValue[0]="on";
						attributeName[0]="Status";
						omnet.updateObjectAttribute(nameObject, attributeValue, istanceName, attributeName);
					}
					omnet.getUpdateFailureRecovery().remove(index);
					index++;
				}
				if(start.iStream.available()>0) {
					start.readFromServer(omnet);
				}
				//if(omnet.endSyncPointAnnounced) {
				//	break;
				//}
				if(omnet.isSyncronizedEnd())
					break;
			}

			//System.out.println("End sync point announced, waiting...");
			// Achieve "end" point synchronization
			//omnet.getRti().synchronizationPointAchieved("end");
			
			// Wait for the federation to be synced
			//while(!omnet.endSyncPointAchieved){
			//	omnet.getRti().evokeMultipleCallbacks(0.1, 1.0);
			//}
			
			omnet.removeInstance();
			start.socketClient.close();
			omnet.resignFederation();
		   	        
	    } catch (IOException IOex) {
	    	System.out.println("ERRORE PS: " + IOex);
	    } catch (Exception e) {
	    	System.out.println("ERRORE PS: " + e);
	   	}
	    
	}
	public Start(String rtiAddress) {
		System.setProperty("portico.lrc.connection", "org.portico.binding.jsop.lrc.JSOPClientConnection"); 
		System.setProperty("portico.lrc.jsop.host", rtiAddress);
		System.out.println(System.getProperty("portico.lrc.jsop.host"));
	
	}	
}
